/*
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
*/

#include "searchthread.h"
#include "constantes.h"

SearchResultItem::SearchResultItem(QString type, QString title, QString context, int pos, QTreeWidgetItem *node)
{
	stType = type;
	stTitle = title;
	stContext = context;
	inPos = pos;
	dataNode = node;
}

SearchThread::SearchThread(QTreeWidget *tree, Model *model)
{
    m_tree = tree;
    m_model = model;
    m_boSearching = false;

    m_results = new QList<SearchResultItem *>();
    m_regExp = new QRegExp("", Qt::CaseSensitive);
}

bool SearchThread::isSearching()
{
    return m_boSearching;
}

bool SearchThread::isSearchInPages()
{
	return m_boSearchInPages;
}

bool SearchThread::isSearchInCategories()
{
	return m_boSearchInCategories;
}

void SearchThread::initSearch(QList<SearchResultItem *> *results, QString searchTerm, bool wholeWord, bool caseSensitive, bool searchPage, bool searchCategory, bool searchTags)
{
	m_results = results;
    m_searchTerm = searchTerm;
    m_boWholeWord = wholeWord;

    m_boSearchInPages = searchPage;
    m_boSearchInCategories = searchCategory;
    m_boSearchInTags = searchTags;

    if (caseSensitive)
    {
        m_caseSensitive = Qt::CaseSensitive;
    }
    else
    {
        m_caseSensitive = Qt::CaseInsensitive;
    }
    m_regExp->setCaseSensitivity(m_caseSensitive);

    if (m_boWholeWord)
        m_regExp->setPattern("\\b" + m_searchTerm + "\\b");
    else
        m_regExp->setPattern(m_searchTerm);    
}

bool SearchThread::match(QString source)
{
    return source.contains(*m_regExp);
}

void SearchThread::processNode(QTreeWidgetItem *item)
{
	SearchResultItem *res;
    int dataIndex = item->data(0, Qt::UserRole).toUInt();
    QString title = m_model->getName(dataIndex);
    QString type = m_model->getType(dataIndex);
    QStringList tags = m_model->getTags(dataIndex).split(","); 

    if ((type == Constantes::TAG_CATEGORY) &&
            (m_boSearchInCategories))
    {
        if (match(title))
        {
            //item->setText(1, "TITLE");
            //m_results->insert(0, item);
            res = new SearchResultItem(Constantes::TAG_CATEGORY, title, tr("Category title."), -1, item);
            m_results->insert(0, res);
        }
    }
    else if ((type == Constantes::TAG_PAGE) &&
             (m_boSearchInPages))
    {
        int pos;

        // We need to transform data into plain text, in case of we search for
        // some kind of HTML or CSS.
        QString data = m_model->getData(dataIndex);
        QTextDocument *document = new QTextDocument(0);
        document->setHtml(data);
        data = document->toPlainText();
        delete document;
        
        if (match(title))
        {
        	res = new SearchResultItem(Constantes::TAG_PAGE, title, tr("Page title."), -1, item);
        	m_results->insert(0, res);
       	}
       	
       	pos = 0;
       	while ((pos = m_regExp->indexIn(data, pos)) != -1)
       	{
       		int startContext = pos - 15;
       		if (startContext < 0)
       			startContext = 0;
       		int endContext = m_regExp->matchedLength() + 30;
       			
       		QString context = "[...] " + data.mid(startContext, endContext) + " [...]";
       		context.replace(QRegExp("\\n"), " ");
       			
       		res = new SearchResultItem(Constantes::TAG_PAGE, title, context, pos, item);
       		m_results->insert(0, res);
       		pos += m_regExp->matchedLength();
      	}
    }

	if (m_boSearchInTags)
	{
		for (int i = 0; i < tags.count(); i++)
		{
			if (match(tags.at(i)))
			{
				res = new SearchResultItem(type, title, tr("Tags"), -1, item);
				m_results->insert(0, res);
			}
		}
	}

    for (int i = 0; i < item->childCount(); i++)
        processNode(item->child(i));
}

void SearchThread::run()
{
    m_boSearching = true;
	
    m_results->clear();

    for (int i = 0; i < m_tree->topLevelItemCount(); i++)
        processNode(m_tree->topLevelItem(i));

    emit searchFinished();
    m_boSearching = false;
}
